package com.ruoyi.user.sms.service;

import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.constant.SecurityConstants;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.system.api.RemoteUserService;
import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.api.model.LoginUser;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.user.user.domain.User;
import com.ruoyi.user.user.service.IUserService;
import com.ruoyi.common.core.web.domain.AjaxResult;
import org.springframework.beans.factory.annotation.Autowired;
import com.ruoyi.user.sms.feign.RemoteAuthService;
import com.ruoyi.user.sms.feign.RemoteRoleService;
import com.ruoyi.user.sms.config.GuoyangSmsProperties;
import com.ruoyi.user.sms.util.HttpUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.security.SecureRandom;
import java.util.concurrent.TimeUnit;
import java.util.Map;
import java.util.HashMap;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

@Service
public class SmsService {

    private static final String KEY_CODE = "login:sms:code:";
    private static final String KEY_SEND = "login:sms:send:";
    private static final String KEY_RETRY = "login:sms:retry:";

    @Resource
    private RedisService redisService;

    @Resource
    private GuoyangSmsProperties smsProperties;

    @Resource
    private RemoteUserService remoteUserService;

    @Autowired
    private IUserService userService;

    @Resource
    private RemoteAuthService remoteAuthService;
    
    @Resource
    private RemoteRoleService remoteRoleService;

    /**
     * 发送登录验证码
     */
    public AjaxResult sendLoginCode(String phone) {
        // 参数校验
        if (StringUtils.isEmpty(phone)) {
            return AjaxResult.error("手机号不能为空");
        }
        
        // 手机号格式校验
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            return AjaxResult.error("手机号格式不正确");
        }

        // 检查发送频率限制（60秒内只能发送一次）
        String sendKey = KEY_SEND + phone;
        if (redisService.hasKey(sendKey)) {
            return AjaxResult.error("发送过于频繁，请60秒后再试");
        }

        // 生成6位数字验证码
        String code = generateCode();
        
        // 存储验证码到Redis，3分钟过期
        String codeKey = KEY_CODE + phone;
        redisService.setCacheObject(codeKey, code, 180L, TimeUnit.SECONDS);
        
        // 设置发送频率限制，60秒过期
        redisService.setCacheObject(sendKey, "1", 60L, TimeUnit.SECONDS);
        
        System.out.println("=== 验证码存储调试 ===");
        System.out.println("手机号: " + phone);
        System.out.println("验证码: " + code);
        System.out.println("存储Key: " + codeKey);
        System.out.println("过期时间: 180秒");
        System.out.println("========================");

        // 发送短信
        try {
            sendSms(phone, code);
            return AjaxResult.success("验证码发送成功");
        } catch (Exception e) {
            // 发送失败，但保留验证码供测试使用
            System.out.println("=== 短信发送失败，但保留验证码供测试 ===");
            System.out.println("手机号: " + phone);
            System.out.println("验证码: " + code);
            System.out.println("请使用此验证码进行登录测试");
            System.out.println("========================");
            
            // 只删除发送频率限制，保留验证码
            redisService.deleteObject(sendKey);
            return AjaxResult.success("验证码已生成，请查看控制台输出");
        }
    }

    /**
     * 发送短信验证码
     */
    private void sendSms(String phone, String code) throws Exception {
        // 检查配置
        if (StringUtils.isEmpty(smsProperties.getAppcode())) {
            throw new IllegalStateException("国阳云短信配置不完整，请检查AppCode配置");
        }

        System.out.println("=== 国阳云短信配置调试 ===");
        System.out.println("appcode: " + (StringUtils.isNotEmpty(smsProperties.getAppcode()) ? "已配置" : "未配置"));
        System.out.println("host: " + smsProperties.getHost());
        System.out.println("path: " + smsProperties.getPath());
        System.out.println("smsSignId: " + smsProperties.getSmsSignId());
        System.out.println("templateId: " + smsProperties.getTemplateId());
        System.out.println("========================");

        String host = smsProperties.getHost();
        String path = smsProperties.getPath();
        String method = "POST";
        String appcode = smsProperties.getAppcode();
        
        // 请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "APPCODE " + appcode);
        headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        
        // 查询参数
        Map<String, String> querys = new HashMap<>();
        querys.put("mobile", phone);
        querys.put("param", "**code**:" + code + ",**minute**:5");
        querys.put("smsSignId", smsProperties.getSmsSignId());
        querys.put("templateId", smsProperties.getTemplateId());
        
        // 请求体（国阳云不需要body参数）
        Map<String, String> bodys = new HashMap<>();

        System.out.println("=== 开始发送国阳云短信 ===");
        System.out.println("手机号: " + phone);
        System.out.println("验证码: " + code);
        System.out.println("========================");

        try {
            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
            String responseBody = EntityUtils.toString(response.getEntity());
            
            System.out.println("=== 短信发送响应 ===");
            System.out.println("状态码: " + response.getStatusLine().getStatusCode());
            System.out.println("响应内容: " + responseBody);
            System.out.println("========================");
            
            // 解析响应
            JSONObject jsonResponse = JSON.parseObject(responseBody);
            String responseCode = jsonResponse.getString("code");
            String message = jsonResponse.getString("msg");
            
            if (!"0".equals(responseCode)) {
                throw new IllegalStateException("短信发送失败: " + message);
            }
            
            System.out.println("=== 短信发送成功 ===");
            System.out.println("短信ID: " + jsonResponse.getString("smsid"));
            System.out.println("余额: " + jsonResponse.getString("balance"));
            System.out.println("========================");
            
        } catch (Exception e) {
            System.out.println("=== 短信发送异常 ===");
            System.out.println("异常类型: " + e.getClass().getSimpleName());
            System.out.println("异常消息: " + e.getMessage());
            System.out.println("手机号: " + phone);
            System.out.println("验证码: " + code);
            System.out.println("请手动输入验证码进行登录测试");
            System.out.println("========================");
            throw e;
        }
    }

    /**
     * 短信登录
     */
    public AjaxResult loginBySms(com.ruoyi.user.sms.dto.SmsLoginRequest req) {
        String phone = req.getPhone();
        String code = req.getCode();

        // 参数校验
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(code)) {
            return AjaxResult.error("手机号和验证码不能为空");
        }

        // 手机号格式校验
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            return AjaxResult.error("手机号格式不正确");
        }

        // 验证码校验
        String codeKey = KEY_CODE + phone;
        String cachedCode = redisService.getCacheObject(codeKey);
        
        System.out.println("=== 验证码校验调试 ===");
        System.out.println("手机号: " + phone);
        System.out.println("输入验证码: " + code);
        System.out.println("Redis中的验证码: " + (cachedCode != null ? cachedCode : "null"));
        System.out.println("验证码Key: " + codeKey);
        System.out.println("========================");
        
        if (StringUtils.isEmpty(cachedCode)) {
            return AjaxResult.error("验证码已过期，请重新获取");
        }

        // 检查重试次数
        String retryKey = KEY_RETRY + phone;
        Integer retryCount = redisService.getCacheObject(retryKey);
        if (retryCount == null) {
            retryCount = 0;
        }

        if (!code.equals(cachedCode)) {
            retryCount++;
            if (retryCount >= 5) {
                // 超过5次错误，删除验证码
                redisService.deleteObject(codeKey);
                redisService.deleteObject(retryKey);
                return AjaxResult.error("验证码错误次数过多，请重新获取");
            } else {
                redisService.setCacheObject(retryKey, retryCount, 300L, TimeUnit.SECONDS);
                return AjaxResult.error("验证码错误，还可重试" + (5 - retryCount) + "次");
            }
        }

        // 验证码正确，删除相关缓存
        redisService.deleteObject(codeKey);
        redisService.deleteObject(retryKey);

        try {
            // 检查系统用户是否存在（通过手机号作为用户名查询）
            R<LoginUser> userResult = remoteUserService.getUserInfo(phone, SecurityConstants.INNER);
            LoginUser loginUser = null;
            boolean isNewUser = false;

            if (R.FAIL == userResult.getCode() || userResult.getData() == null) {
                // 系统用户不存在，创建新用户
                isNewUser = true;
                
                SysUser sysUser = new SysUser();
                sysUser.setUserName(phone);  // 用户名设置为手机号
                sysUser.setNickName(phone);
                sysUser.setPhonenumber(phone);
                sysUser.setStatus("0"); // 正常状态
                sysUser.setPwdUpdateDate(DateUtils.getNowDate());
                
                // 注册系统用户
                R<?> reg = remoteUserService.registerUserInfo(sysUser, SecurityConstants.INNER);
                if (R.FAIL == reg.getCode()) {
                    return AjaxResult.error(500, "注册系统账户失败: " + reg.getMsg());
                }
                
                // 重新获取用户信息（通过手机号作为用户名查询）
                userResult = remoteUserService.getUserInfo(phone, SecurityConstants.INNER);
                if (R.FAIL == userResult.getCode() || userResult.getData() == null) {
                    return AjaxResult.error("获取用户信息失败");
                }
                loginUser = userResult.getData();
                
                
                // 分配默认角色
                try {
                    // 使用 sysUser.getUserId() 而不是 loginUser.getUserid()
                    Long userId = loginUser.getSysUser().getUserId();
                    
                    Map<String, Object> roleBody = new HashMap<>();
                    roleBody.put("userId", userId);
                    roleBody.put("roleIds", java.util.Arrays.asList(101L)); // 默认用户角色，使用List
                    
                    R<Void> roleResult = remoteRoleService.assignUserRole(roleBody, SecurityConstants.INNER);
                    if (R.SUCCESS == roleResult.getCode()) {
                        System.out.println("用户角色分配成功");
                    } else {
                        System.out.println("用户角色分配失败: " + roleResult.getMsg());
                    }
                } catch (Exception e) {
                    System.out.println("用户角色分配异常: " + e.getMessage());
                    e.printStackTrace();
                }
            } else {
                loginUser = userResult.getData();
            }

            // 检查业务用户是否存在
            User user = userService.selectUserByPhone(phone);
            Long userId = null;
            
            if (user == null) {
                // 创建业务用户
                user = new User();
                user.setPhone(phone);
                user.setRegTime(DateUtils.getNowDate());
                user.setDeleted(0);
                userService.insertUser(user);
                userId = user.getId();
            } else {
                userId = user.getId();
            }

            // 生成Token
            Map<String, String> payload = new HashMap<>();
            payload.put("phone", phone);
            payload.put("userId", userId.toString());
            
            R<Map<String, Object>> tokenResult = remoteAuthService.smsToken(payload);
            if (R.FAIL == tokenResult.getCode()) {
                return AjaxResult.error("生成Token失败: " + tokenResult.getMsg());
            }

            Map<String, Object> tokenData = tokenResult.getData();
            String token = (String) tokenData.get("access_token");
            Integer expiresIn = (Integer) tokenData.get("expires_in");

            // 返回登录结果
            Map<String, Object> result = new HashMap<>();
            result.put("token", token);
            result.put("userId", userId);
            result.put("phone", phone);
            result.put("expiresIn", expiresIn);
            result.put("isNewUser", isNewUser);

            return AjaxResult.success("登录成功", result);

        } catch (Exception e) {
            return AjaxResult.error("登录失败: " + e.getMessage());
        }
    }

    /**
     * 生成6位数字验证码
     */
    private String generateCode() {
        SecureRandom random = new SecureRandom();
        int code = 100000 + random.nextInt(900000);
        return String.valueOf(code);
    }
}